
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>

#define NF_QUEUE_NUM 5
#define QUEUER_BUF_SIZE 1500

typedef struct tcpheader_t {
    uint32_t    saddr;
    uint32_t    daddr;
    uint16_t    sport;
    uint16_t    dport;
    uint8_t     tos;
    uint8_t     ttl;
    uint32_t    sync_time;
}tcpheader_t;

struct tcpheader_t tcpheader;

struct ipv4_packet
{
    struct iphdr iph;
    struct tcphdr tcph;
};

int ip_to_str(char *ipstr, uint32_t ipval)
{
    int offset = 0;
    for (int i = 0; i < 4; i++) {
        offset += sprintf(ipstr + offset, "%d.", ((uint8_t*)(&ipval))[3-i]);
    }
    ipstr[offset-1] = 0;
}

/* NFQUEUE callback function for incoming TCP syn */
static int nfqueue_get_syn(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data)
{
    printf("callback nfqueue_get_syn()\n");

    unsigned char *buffer = NULL;
    struct ipv4_packet *ip4 = NULL;
    int id = 0, ret = 0;
    struct nfqnl_msg_packet_hdr *ph = NULL;

    // 获取packet header
    ph = nfq_get_msg_packet_hdr(nfa);
    if (!ph) {
        printf("Unable to get packet header!");
        return -1;
    }
    id = ntohl(ph->packet_id);

    // 获取有效载荷
    ret = nfq_get_payload(nfa, &buffer);
    ip4 = (struct ipv4_packet *)buffer;

    tcpheader.saddr = ntohl(ip4->iph.saddr);
    tcpheader.daddr = ntohl(ip4->iph.daddr);
    tcpheader.sport = ntohs(ip4->tcph.source);
    tcpheader.dport = ntohs(ip4->tcph.dest);
    tcpheader.tos = ip4->iph.tos;
    tcpheader.ttl = ip4->iph.ttl;
    // tcpheader.sync_time = time(NULL);

    // debug print
    char sipbuf[20] = {0}, dipbuf[20] = {0};
    ip_to_str(sipbuf, tcpheader.saddr);
    ip_to_str(dipbuf, tcpheader.daddr);
    // printf("src[%u:%u]-tos[%u]-ttl[%u] dst[%u:%u]\n", tcpheader.saddr, tcpheader.sport, tcpheader.tos, tcpheader.ttl, tcpheader.daddr, tcpheader.dport);
    printf("src[%s:%u] tos[%u]-ttl[%u] dst[%s:%u]\n", sipbuf, tcpheader.sport, tcpheader.tos, tcpheader.ttl, dipbuf, tcpheader.dport);
    printf("\n");

    return 0;
}
void main()
{
    printf("Opening NFQ library handle\n");

    // 打开nfq
    struct nfq_handle *h = nfq_open();
    if (!h) {
        perror("Failed to open NFQ handler!\n");
        exit(1);
    }

    // 解绑已经存在的队列
    printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
    nfq_unbind_pf(h, AF_INET);

    // 绑定自定义创建的队列
    printf("binding nfnetlink_queue to AF_INET\n");
    if (nfq_bind_pf(h, AF_INET) < 0) {
        perror("nfq_bind_pf\n");
        exit(1);
    }

    // 创建从队列收到数据的回调处理函数
    printf("binding this socket to queue '%d'\n", NF_QUEUE_NUM);
    struct nfq_q_handle *qh = nfq_create_queue(h, NF_QUEUE_NUM, &nfqueue_get_syn, NULL);
    if (!qh) {
        perror("Failed to create nfnetlink queue!\n");
        exit(1);
    }

    // 设置包的处理模式
    printf("setting copy_packet mode\n");
    int ret = nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff);
    if (ret < 0) {
        printf("Failed to setup NFQ packet_copy mode! [RET = %d]\n", ret);
        exit(1);
    }

    struct nfnl_handle *nh = nfq_nfnlh(h);
    int fd = nfnl_fd(nh);

    ssize_t rc;
    char buf[QUEUER_BUF_SIZE];
    while ((rc = recv(fd, buf, QUEUER_BUF_SIZE, 0)) >= 0) {
        // printf("received packet [sz = %ld]\n", rc);
        nfq_handle_packet(h, buf, rc);
    }

    printf("Exiting [rc=%ld]\n", rc);
    nfq_close(h);
}